-- 交易事件监听与参数捕获
-- 目标：监听 GameEvents/TradeEvents、GameEvents/Gift 以及 GameEvents 根目录下与交易/礼物/宠物相关的 RemoteEvent/RemoteFunction
-- 同时拦截 FireServer/InvokeServer，安全打印方法名与参数

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HttpService = game:GetService("HttpService")

local LocalPlayer = Players.LocalPlayer

-- 日志
local function log(message)
	print("[捕获] " .. message)
	local ok = pcall(function()
		appendfile("trade_capture_log.txt", "[捕获] " .. message .. "\n")
	end)
	if not ok then
		pcall(function()
			writefile("trade_capture_log.txt", "[捕获] " .. message .. "\n")
		end)
	end
end

-- 安全序列化参数
local function safeSerialize(value)
	local t = typeof(value)
	if t == "Instance" then
		return {
			type = t,
			class = value.ClassName,
			name = value.Name,
			path = tostring(value),
		}
	elseif t == "table" then
		local ok, encoded = pcall(function()
			return HttpService:JSONEncode(value)
		end)
		if ok then
			return { type = t, json = encoded }
		else
			-- 回退：浅拷贝键类型
			local shallow = {}
			local count = 0
			for k, v in pairs(value) do
				count = count + 1
				if count > 50 then break end
				shallow[tostring(k)] = typeof(v)
			end
			return { type = t, preview = shallow }
		end
	elseif t == "Vector3" or t == "Vector2" or t == "CFrame" or t == "Color3" then
		return { type = t, value = tostring(value) }
	else
		return { type = t, value = tostring(value) }
	end
end

local function serializeArgs(args)
	local out = {}
	for i, arg in ipairs(args) do
		out[i] = safeSerialize(arg)
	end
	local ok, json = pcall(function()
		return HttpService:JSONEncode(out)
	end)
	if ok then return json end
	return "[args JSON encode failed]"
end

-- 监听 OnClientEvent
local function getFullPath(inst)
	local parts = {}
	local current = inst
	while current do
		table.insert(parts, 1, current.Name)
		current = current.Parent
		if current == game then break end
	end
	return table.concat(parts, "/")
end

local function attachListener(remote)
	if remote:IsA("RemoteEvent") then
		remote.OnClientEvent:Connect(function(...)
			local args = { ... }
			log("🟡 OnClientEvent path=" .. getFullPath(remote) .. " argCount=" .. #args .. " args=" .. serializeArgs(args))
		end)
	elseif remote:IsA("RemoteFunction") then
		remote.OnClientInvoke = function(...)
			local args = { ... }
			log("🟡 OnClientInvoke path=" .. getFullPath(remote) .. " argCount=" .. #args .. " args=" .. serializeArgs(args))
			-- 不改变行为：不处理返回值，由上层函数实现
		end
	end
end

-- 目标筛选
local function isTargetRemote(inst)
	if not inst then return false end
	local name = inst.Name or ""
	if name:match("Trade") or name:match("Gift") or name:match("Pet") then
		return true
	end
	-- 精确匹配已知清单
	local whitelist = {
		RespondRequest = true,
		SendRequest = true,
		UpdateTradeState = true,
		Accept = true,
		Decline = true,
		AddItem = true,
		RemoveItem = true,
		Confirm = true,
		SetSheckles = true,
		SendGiftTo = true,
		GiftPrompted = true,
		FriendGiftEvent = true,
		ActivePetService = true,
		PetsService = true,
		BuyPetEgg = true,
		PetEggService = true,
		PetGiftingService = true,
		PetZoneAbility = true,
		GiftPet = true,
		AcceptPetGift = true,
		PetSkipped = true,
		UnlockSlotFromPet = true,
		RefreshActivePetsUI = true,
		RefreshPetModel = true,
		PetBoostService = true,
		PetMutationHandler = true,
		PetMutationMachineService_RE = true,
		PetMutationClaimAnimation = true,
		PetShardService_RE = true,
		RequestPetCooldowns = true,
		PetCooldownsUpdated = true,
		PetNameRerollerActivated = true,
		PetLeadService_RE = true,
		SellPet_RE = true,
		SellAllPets_RE = true,
		PetPouchUse = true,
	}
	return whitelist[name] == true
end

-- 遍历并绑定监听
local function bindAll()
	local gameEvents = ReplicatedStorage:FindFirstChild("GameEvents")
	if not gameEvents then
		log("❌ 未找到 GameEvents")
		return
	end

	-- TradeEvents
	local tradeEvents = gameEvents:FindFirstChild("TradeEvents")
	if tradeEvents then
		for _, child in ipairs(tradeEvents:GetChildren()) do
			if (child:IsA("RemoteEvent") or child:IsA("RemoteFunction")) and isTargetRemote(child) then
				log("🔗 监听 TradeEvents." .. child.Name)
				attachListener(child)
			end
		end
	end

	-- Gift
	local giftFolder = gameEvents:FindFirstChild("Gift")
	if giftFolder then
		for _, child in ipairs(giftFolder:GetChildren()) do
			if (child:IsA("RemoteEvent") or child:IsA("RemoteFunction")) and isTargetRemote(child) then
				log("🔗 监听 Gift." .. child.Name)
				attachListener(child)
			end
		end
	end

	-- 根目录（筛交易/礼物/宠物相关）
	for _, child in ipairs(gameEvents:GetChildren()) do
		if (child:IsA("RemoteEvent") or child:IsA("RemoteFunction")) and isTargetRemote(child) then
			log("🔗 监听 GameEvents." .. child.Name)
			attachListener(child)
		end
	end

	-- 额外：遍历 ReplicatedStorage 下的所有 Remote 并绑定，扩大覆盖范围
	for _, desc in ipairs(ReplicatedStorage:GetDescendants()) do
		if desc:IsA("RemoteEvent") or desc:IsA("RemoteFunction") then
			log("🔗 监听 RS路径 " .. getFullPath(desc))
			attachListener(desc)
		end
	end

	-- ProximityPrompt（靠近交互提示）监听
	local function attachPrompt(prompt)
		if not prompt or not prompt:IsA("ProximityPrompt") then return end
		local info = string.format("path=%s ActionText=%s ObjectText=%s Hold=%.2f Key=%s Gamepad=%s", 
			getFullPath(prompt), tostring(prompt.ActionText), tostring(prompt.ObjectText), 
			prompt.HoldDuration or 0, tostring(prompt.KeyboardKeyCode), tostring(prompt.GamepadKeyCode))
		log("🔗 监听 ProximityPrompt " .. info)
		prompt.PromptShown:Connect(function(player)
			log("🟡 PromptShown " .. info .. " player=" .. (player and player.Name or "nil"))
		end)
		prompt.PromptHidden:Connect(function(player)
			log("🟡 PromptHidden " .. info .. " player=" .. (player and player.Name or "nil"))
		end)
		prompt.Triggered:Connect(function(player)
			log("🔴 PromptTriggered " .. info .. " player=" .. (player and player.Name or "nil"))
		end)
	end

	for _, d in ipairs(workspace:GetDescendants()) do
		if d:IsA("ProximityPrompt") then
			attachPrompt(d)
		end
	end

	workspace.DescendantAdded:Connect(function(inst)
		if inst:IsA("ProximityPrompt") then
			attachPrompt(inst)
		end
	end)
end

-- __namecall 拦截 FireServer/InvokeServer
local function hookNamecall()
	local mt = getrawmetatable(game)
	if not mt then return end
	local old = mt.__namecall
	setreadonly(mt, false)
	mt.__namecall = function(self, ...)
		local method = getnamecallmethod and getnamecallmethod() or ""
		local args = { ... }
		local ok, _ = pcall(function()
			if (method == "FireServer" or method == "InvokeServer") then
				-- 记录所有远程调用，并附带路径，便于回溯
				log("🔴 call path=" .. getFullPath(self) .. " method=" .. method .. " argCount=" .. #args .. " args=" .. serializeArgs(args))
			end
		end)
		if not ok then
			-- 忽略日志失败
		end
		return old(self, ...)
	end
	setreadonly(mt, true)
end

-- 主入口
local function main()
	log("交易事件监听器已启动")
	bindAll()
	hookNamecall()

	-- 额外：使用 hookmetamethod 和 hookfunction 扩大拦截覆盖
	local function tryAdvancedHooks()
		local ok = pcall(function()
			-- 优先使用 hookmetamethod，如果环境提供
			if hookmetamethod and getnamecallmethod and newcclosure then
				local oldNamecall
				oldNamecall = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
					local method = getnamecallmethod()
					local args = { ... }
					local success, _ = pcall(function()
						if (method == "FireServer" or method == "InvokeServer") then
							log("🔴 hm call path=" .. getFullPath(self) .. " method=" .. method .. " argCount=" .. #args .. " args=" .. serializeArgs(args))
						end
					end)
					if not success then end
					return oldNamecall(self, ...)
				end))
			end

			-- 再尝试直接 hook RemoteEvent:FireServer 与 RemoteFunction:InvokeServer
			if hookfunction and newcclosure then
				-- 为了避免递归，使用简单的重入保护
				local inFire = false
				local inInvoke = false

				local oldFireServer = hookfunction(Instance.new("RemoteEvent").FireServer, newcclosure(function(self, ...)
					if not inFire then
						inFire = true
						local args = { ... }
						pcall(function()
							log("🔴 hf RemoteEvent path=" .. getFullPath(self) .. " method=FireServer argCount=" .. #args .. " args=" .. serializeArgs(args))
						end)
						inFire = false
					end
					return oldFireServer(self, ...)
				end))

				local rf = Instance.new("RemoteFunction")
				rf.Name = "_tmpRF_"
				local oldInvokeServer = hookfunction(rf.InvokeServer, newcclosure(function(self, ...)
					if not inInvoke then
						inInvoke = true
						local args = { ... }
						pcall(function()
							log("🔴 hf RemoteFunction path=" .. getFullPath(self) .. " method=InvokeServer argCount=" .. #args .. " args=" .. serializeArgs(args))
						end)
						inInvoke = false
					end
					return oldInvokeServer(self, ...)
				end))
				-- 清理临时对象
				rf:Destroy()
			end
		end)
		if ok then
			log("高级拦截已启用 (hookmetamethod / hookfunction)")
		else
			log("高级拦截不可用，继续使用基础 __namecall 钩子")
		end
	end

	tryAdvancedHooks()
	log("已绑定监听并拦截 FireServer/InvokeServer")

	-- 动态监听后续新复制下来的远程对象
	ReplicatedStorage.DescendantAdded:Connect(function(inst)
		if inst:IsA("RemoteEvent") or inst:IsA("RemoteFunction") then
			log("🔗 动态监听 RS路径 " .. getFullPath(inst))
			attachListener(inst)
		end
	end)
end

main()


